/*
 * nlsync
 * Copyright (c) 2010 apechurin 
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;

namespace nlsync.XlsOld
{
    /// <summary>
    /// Implementation of the IStringCatalog interface which uses 
    /// a single Xls file to store all strings of all bundles of some culture.
    /// The Xls structure:
    /// - the first line is not used (used for columns headers);
    /// - column A used for relative path to Resx file where the string declared.
    ///     The path is relative to the project root folder. It's a bundle name;
    /// - column B is a string name;
    /// - column C is a default culture string value;
    /// - column D is a translated string value;
    /// - column E is a string comment.
    /// THIS IMPLEMENTATION IS DEPRECATED. SEE Xls NAMESPACE.
    /// </summary>
    public class XlsStringCatalog : IStringCatalog
    {
        #region Internal properties

        /// <summary>
        /// Gets the settings.
        /// </summary>
        internal ISettings Settings
        {
            get
            {
                return mSettings;
            }
        }
        private ISettings mSettings;

        /// <summary>
        /// Gets the Excel application.
        /// </summary>
        internal Excel.Application XlsApplication
        {
            get
            {
                return mApplication;
            }
        }
        private Excel.Application mApplication;

        /// <summary>
        /// Gets the Excel workbook.
        /// </summary>
        internal Excel.Workbook XlsWorkbook
        {
            get
            {
                return mWorkbook;
            }
        }
        private Excel.Workbook mWorkbook;

        /// <summary>
        /// Gets the Excel sheet with data.
        /// </summary>
        internal Excel.Worksheet Worksheet
        {
            get
            {
                return mSheet;
            }
        }
        private Excel.Worksheet mSheet;

        #endregion

        #region Constructors and finalizer

        /// <summary>
        /// Constructor. Can throw Exception.
        /// </summary>
        /// <param name="source">The path to an Xls file</param>
        /// <param name="settings">The settings.</param>
        public XlsStringCatalog(string source, ISettings settings)
        {
            mSettings = settings;
            
            // open the Xls file
            mApplication = new Excel.Application();
            
            mApplication.Visible = false;
            mApplication.ScreenUpdating = false;

            Excel.Workbooks workbooks = mApplication.Workbooks;
            mWorkbook = workbooks.Open(Path.GetFullPath(source), 
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing);

            // get the first sheet
            Excel.Sheets sheets = mWorkbook.Sheets;
            mSheet = (Excel.Worksheet)sheets[1];
        }

        /// <summary>
        /// Constructor. Creates a new excel. For unittesting purpose only.
        /// </summary>
        /// <param name="settings">The settings</param>
        internal XlsStringCatalog(ISettings settings)
        {
            mSettings = settings;

            // create the Xls file
            mApplication = new Excel.Application();

            mApplication.Visible = true;
            mApplication.ScreenUpdating = true;

            Excel.Workbooks workbooks = mApplication.Workbooks;
            mWorkbook = workbooks.Add(Type.Missing);

            // get the first sheet
            Excel.Sheets sheets = mWorkbook.Sheets;
            mSheet = (Excel.Worksheet)sheets[1];
        }

        /// <summary>
        /// Finalizer.
        /// </summary>
        ~XlsStringCatalog()
        {
            Close();
        }

        #endregion

        #region IStringCatalog methods

        public IEnumerable<String> BundleNames
        {
            get
            {
                IList<string> bundleNames = new List<string>();
                
                // get the range of cells in the bundle_names column
                Excel.Range lastCell = Worksheet.get_Range("a65536", Type.Missing).
                    get_End(Excel.XlDirection.xlUp);
                Excel.Range sources = Worksheet.get_Range("a2", lastCell);

                // get all values in a single managed array
                object[,] values = (object[,])sources.get_Value(
                    Excel.XlRangeValueDataType.xlRangeValueDefault);

                int lower0 = values.GetLowerBound(0);
                int upper0 = values.GetUpperBound(0);
                int lower1 = values.GetLowerBound(1);
                
                // find all unique value and return them
                for (int i = lower0; i <= upper0; i++)
                { 
                    object t = values[i, lower1];
                    if (t == null)
                        continue;
                    string bundleName = t.ToString();

                    if (bundleNames.IndexOf(bundleName) < 0)
                        bundleNames.Add(bundleName);
                }

                return bundleNames;
            }
        }

        public void Close()
        {
            try
            {
                if (mApplication != null)
                {
                    if (mWorkbook != null)
                    {
                        // for unittests - prevents saving
                        if (mWorkbook.Path == null || mWorkbook.Path.Length == 0)
                            mWorkbook.Saved = true;

                        if (!mWorkbook.Saved)
                            mWorkbook.Save();
                    }

                    mApplication.Quit();
                    mApplication = null;
                }
            }
            catch (Exception)
            { 
            }
        }

        public IStringBundle GetBundle(string name)
        {
            return new XlsStringBundle(name, this);
        }

        #endregion

        /// <summary>
        /// Clears the contents of the sheet. For unit tests.
        /// </summary>
        internal void ClearSheet()
        {
            mSheet.Cells.Delete(Excel.XlDirection.xlUp);
        }
    }
}
